#include <ace/xcomponent/native_interface_xcomponent.h>
#include <native_buffer/native_buffer.h>
#include <native_drawing/drawing_canvas.h>
#include <native_drawing/drawing_color.h>
#include <native_drawing/drawing_path.h>
#include <native_drawing/drawing_pen.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <native_image/native_image.h>
#include <native_window/external_window.h>
#include <native_drawing/drawing_gpu_context.h>
#include <native_drawing/drawing_surface.h>
#include <queue>
#include <thread>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include "testing/Testing.h"
#include "napi/native_api.h"
#include "testing/DrawTesting.h"
#include "include/oh/OHEnv.h"

#include "utils/log.h"
#include <poll.h>
#include <unistd.h>
#include <arkui/native_node_napi.h>
#include "oh/OHRenderNode.h"



static DrawTesting g_nativeTesting;

static OH_NativeXComponent *g_nativeXcomponent = nullptr;
static OHNativeWindow *g_nativeWindow = nullptr;
static OH_Drawing_GpuContext *g_gpuContext = nullptr;
static OH_Drawing_Image_Info g_gpuSurfaceInfo = {0, 0, OH_Drawing_ColorFormat::COLOR_FORMAT_RGBA_8888,
                                                 OH_Drawing_AlphaFormat::ALPHA_FORMAT_PREMUL};
static OH_Drawing_Surface *g_gpuSurface = nullptr;
static OH_Drawing_Canvas *g_gpuCanvas = nullptr;

static std::map<uint64_t, char *> g_native_buffer_ptrs;
static std::map<uint64_t, OH_NativeBuffer *> g_native_buffer_maps;
std::queue<uint64_t> buffer_id_queue;


static bool CPUWaitFence(int fence_fd, uint32_t timeout) {
  if (fence_fd <= 0) {
    return false;
  }
  struct pollfd poll_fd = {0};
  poll_fd.fd = fence_fd;
  poll_fd.events = POLLIN;

  int ret = -1;
  do {
    ret = poll(&poll_fd, 1, timeout);
  } while (ret == -1 && (errno == EINTR || errno == EAGAIN));

  if (ret == 0) {
    ret = -1;
    errno = ETIME;
  } else if (ret > 0) {
    ret = 0;
    if (poll_fd.revents & (POLLERR | POLLNVAL)) {
      ret = -1;
      errno = EINVAL;
    }
  }
  return ret < 0 ? -errno : 0;
}

static void FlushXcomponentBuffer(OH_Drawing_Canvas *canvas) {

    if (g_nativeWindow) {
        OHNativeWindowBuffer *buffer = nullptr;
        int fence_fd;
        int ret = OH_NativeWindow_NativeWindowRequestBuffer(g_nativeWindow, &buffer, &fence_fd);
        CPUWaitFence(fence_fd, -1);
        close(fence_fd);
        if (ret != 0) {
            LOGD("request buffer get error %{public}d", ret);
        }

        OH_NativeBuffer *native_buffer = nullptr;
        OH_NativeBuffer_FromNativeWindowBuffer(buffer, &native_buffer);

        OH_NativeBuffer_Config nativebuffer_config;

        OH_NativeBuffer_GetConfig(native_buffer, &nativebuffer_config);
        uint32_t seq_id = OH_NativeBuffer_GetSeqNum(native_buffer);
        LOGD("flush buffer_id_queue size %{public}d %{public}d", (int)buffer_id_queue.size(), seq_id);
        char *dst = nullptr;
        if (g_native_buffer_ptrs.find(seq_id) == g_native_buffer_ptrs.end()) {
            OH_NativeBuffer_Map(native_buffer, (void **)&dst);
            g_native_buffer_ptrs[seq_id] = dst;
            buffer_id_queue.push(seq_id);
            LOGE("buffer_id_queue size %{public}d", (int)buffer_id_queue.size());
            if (buffer_id_queue.size() > 5) {
                uint64_t delete_id = buffer_id_queue.front();
                buffer_id_queue.pop();
                g_native_buffer_ptrs.erase(delete_id);
                OH_NativeBuffer *delete_buffer = g_native_buffer_maps[delete_id];
                if (delete_buffer) {
                LOGE("delete_buffer ");

                    OH_NativeBuffer_Unmap(delete_buffer);
                }
                g_native_buffer_maps.erase(delete_id);
            }
        }
        
        if (dst) {
            LOGD("read pixel %{public}d %{public}d", g_gpuSurfaceInfo.width, g_gpuSurfaceInfo.height);
            OH_Drawing_CanvasReadPixels(canvas, &g_gpuSurfaceInfo, dst, nativebuffer_config.stride, 0, 0);
        }

        // map/unmap is time consuming
        // drawPixelmap will get mem leak.
//         OH_NativeBuffer_Unmap(native_buffer);

        if (buffer != nullptr) {
            OH_NativeWindow_NativeWindowFlushBuffer(g_nativeWindow, buffer, -1, {});
        }
    }
}

static OH_Drawing_Canvas *GetGpuSurfaceCanvas(int width, int height) {
    if (width == 0 || height == 0 || g_gpuContext == nullptr) {
        LOGE("width ${public}d height ${public}d context %{public}x", width, height, g_gpuContext);
        return nullptr;
    }
    if (width != g_gpuSurfaceInfo.height || height != g_gpuSurfaceInfo.height) {
        if (g_gpuSurface) {
            OH_Drawing_SurfaceDestroy(g_gpuSurface);
        }
        g_gpuSurfaceInfo.width = width;
        g_gpuSurfaceInfo.height = height;
        g_gpuSurface = OH_Drawing_SurfaceCreateFromGpuContext(g_gpuContext, true, g_gpuSurfaceInfo);
        g_gpuCanvas = OH_Drawing_SurfaceGetCanvas(g_gpuSurface);
    }
    if (g_gpuSurface) {
        return g_gpuCanvas;
    } else {
        LOGE("g_gpuSurface get null");
        return nullptr;
    }
}

static void NativeDrawCallback(OH_NativeXComponent *component, uint64_t timestamp, uint64_t targetTimestamp) {

    LOGD("Gpu context %{public}x window %{public}x", g_gpuContext, g_nativeWindow);
    if (!g_nativeWindow) {
        return;
    }
    uint64_t width = 0, height = 0;
    OH_NativeWindow_NativeWindowHandleOpt(g_nativeWindow, GET_BUFFER_GEOMETRY, &height, &width);


    OH_Drawing_Canvas *canvas = GetGpuSurfaceCanvas(width, height);
    if (canvas == nullptr) {
        return;
    }
//     g_nativeTesting.SetDrawCanvas(canvas);
//     g_nativeTesting.DrawLists(0, 0, width, height, 20);
    
    Testing::GetInstance().setDrawCanvas(canvas, width, height);
    Testing::GetInstance().startTesting();
    FlushXcomponentBuffer(canvas);
}

static napi_value OnDraw(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    int32_t id;
    napi_get_value_int32(env, args[0], &id);

    // 获取 Canvas 指针
    void *temp = nullptr;
    napi_unwrap(env, args[1], &temp);
    OH_Drawing_Canvas *canvas = reinterpret_cast<OH_Drawing_Canvas *>(temp);

    // 获取 Canvas 宽度
    int32_t width;
    napi_get_value_int32(env, args[2], &width);

    // 获取 Canvas 高度
    int32_t height;
    napi_get_value_int32(env, args[3], &height);

    LOGI("native size : %{public}d %{public}d", width, height);
    
    OHEnv::GetInstance()->SetEnv(env);
    Testing::GetInstance().setDrawCanvas(canvas, width, height);
    Testing::GetInstance().startTesting();
    
//     g_nativeTesting.SetDrawCanvas(canvas);
//     g_nativeTesting.DrawLists(0, 0, width, height, 20);
    
    
//     uv_loop_t* platform_loop = nullptr;
//     int status = napi_get_uv_event_loop(env, &platform_loop);

    return nullptr;
}


static napi_value NativeTouchMove(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    int32_t type;
    napi_get_value_int32(env, args[0], &type);


    int32_t x;
    napi_get_value_int32(env, args[1], &x);

    int32_t y;
    napi_get_value_int32(env, args[2], &y);
    
    int32_t id;
    napi_get_value_int32(env, args[3], &id);

//     LOGI("native move : %{public}d %{public}d", x, y);
//     g_nativeTesting.TouchMove(type, x, y);
    Testing::GetInstance().touchPointMove(type, x, y, id);

    return nullptr;
}

static napi_value NativeAddPixelmap(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    OH_PixelmapNative *pixelmap = nullptr;
    if (OH_PixelmapNative_ConvertPixelmapNativeFromNapi(env, args[0], &pixelmap) != IMAGE_SUCCESS) {
        return nullptr;
    }
    Testing::GetInstance().addPixelmapData(pixelmap);
    
//    NativePixelMap *nativePixelMap = OH_PixelMap_InitNativePixelMap(env, args[0]);

//     g_nativeTesting.AddPixelmap(nativePixelMap);

    return nullptr;
}


static napi_value Add(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);


    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;
}


static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) {
    OHNativeWindow *nativeWindow = (OHNativeWindow *)window;
    uint64_t width, height;
    OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);

    LOGD("OnSurfaceCreatedCB %{public}lld %{public}lld", width, height);

    g_nativeWindow = nativeWindow;

    OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_USAGE,
                                          NATIVEBUFFER_USAGE_HW_TEXTURE | NATIVEBUFFER_USAGE_HW_RENDER |
                                              NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE |
                                              NATIVEBUFFER_USAGE_MEM_DMA);

    OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, width, height);

    OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, NATIVEBUFFER_PIXEL_FMT_RGBA_8888);

    return;
}

static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) {}

static void DispatchEventCB(OH_NativeXComponent *component, void *window) {
    LOGD("touch event");
    if (g_nativeXcomponent) {
        OH_NativeXComponent_ExpectedRateRange range = {120, 120, 120};
        OH_NativeXComponent_SetExpectedFrameRateRange(component, &range);
        OH_NativeXComponent_RegisterOnFrameCallback(g_nativeXcomponent, NativeDrawCallback);

        if (!g_gpuContext) {
            OH_Drawing_GpuContextOptions options;
            options.allowPathMaskCaching = true;
            g_gpuContext = OH_Drawing_GpuContextCreateFromGL(options);
        }


        LOGD("StartDraw");
    }
    LOGD("touch event end");
}


static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { g_nativeWindow = nullptr; }

OH_NativeXComponent_Callback g_Xcallback = {};

static void InitEGL() {
    static EGLDisplay eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (eglDisplay_ == EGL_NO_DISPLAY) {
        return;
    }

    EGLint majorVersion, minorVersion;
    if (!eglInitialize(eglDisplay_, &majorVersion, &minorVersion)) {
        LOGE("Failed to init egl");
        return;
    }

    const EGLint configAttribs[] = {EGL_SURFACE_TYPE,
                                    EGL_WINDOW_BIT,
                                    EGL_RED_SIZE,
                                    8,
                                    EGL_GREEN_SIZE,
                                    8,
                                    EGL_BLUE_SIZE,
                                    8,
                                    EGL_ALPHA_SIZE,
                                    8,
                                    EGL_RENDERABLE_TYPE,
                                    EGL_OPENGL_ES2_BIT,
                                    EGL_NONE};

    EGLint numConfigs;
    EGLConfig eglConfig_;
    if (!eglChooseConfig(eglDisplay_, configAttribs, &eglConfig_, 1, &numConfigs)) {
        LOGE("Failed to choose EGL config");
        return;
    }

    EGLint attribList[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
    EGLDisplay eglSurface = eglCreatePbufferSurface(eglDisplay_, eglConfig_, attribList);
    if (eglSurface == EGL_NO_SURFACE) {
        LOGE("Failed to create EGL surface");
        return;
    }

    EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};

    EGLContext eglContext = eglCreateContext(eglDisplay_, eglConfig_, EGL_NO_CONTEXT, contextAttribs);
    if (eglContext == EGL_NO_CONTEXT) {
        LOGE("Failed to create EGL context");
        return;
    }

    if (!eglMakeCurrent(eglDisplay_, eglSurface, eglSurface, eglContext)) {
        LOGE("Failed to make EGL context current");
        return;
    }
}

static napi_value NativeAddPicData(napi_env env, napi_callback_info info) {
    // TODO: implements the code;
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    void* picData = nullptr;
    size_t length = 0;

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    napi_get_arraybuffer_info(env, args[0], &picData, &length);
    
    Testing::GetInstance().addPicData(picData, length);

    return nullptr;
}

static napi_value NativeAddGifData(napi_env env, napi_callback_info info) {
    // TODO: implements the code;
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    void* picData = nullptr;
    size_t length = 0;

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    napi_get_arraybuffer_info(env, args[0], &picData, &length);
    
    Testing::GetInstance().addGifData(picData, length);

    return nullptr;
}

static napi_value NativeSetFontPath(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_status status;

    status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    if (status != napi_ok || argc < 1) {
        napi_throw_type_error(env, nullptr, "Expected one string argument");
        return nullptr;
    }

    napi_valuetype argType;
    status = napi_typeof(env, argv[0], &argType);
    if (status != napi_ok || argType != napi_string) {
        napi_throw_type_error(env, nullptr, "Argument must be a string");
        return nullptr;
    }

    size_t str_length;
    status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &str_length);
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "Failed to get string length");
        return nullptr;
    }

    char *path = new char[str_length + 1];
    status = napi_get_value_string_utf8(env, argv[0], path, str_length + 1, nullptr);
    if (status != napi_ok) {
        delete[] path;
        napi_throw_error(env, nullptr, "Failed to extract string");
        return nullptr;
    }

    Testing::GetInstance().setFontPath(path);

    delete[] path;

    napi_value result;
    status = napi_get_undefined(env, &result);
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "Failed to return undefined");
        return nullptr;
    }

    return result;
}
//
//static napi_value SetRenderNode(napi_env env, napi_callback_info info) {
//    size_t argc = 1;
//    napi_value argv[1];
//    napi_status status;
//
//    status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
//    if (status != napi_ok || argc < 1) {
//        napi_throw_type_error(env, nullptr, "Expected one string argument");
//        return nullptr;
//    }
//    
//    ArkUI_NodeHandle handle = nullptr;
//    int ret = OH_ArkUI_GetNodeHandleFromNapiValue(env, argv[0], &handle);
//    LOGD("napi value ret = %{public}d", ret);
//    
//    napi_value result;
//    status = napi_get_property_names(env, argv[0], &result);
//    if (status != napi_ok) {
//        napi_throw_error(env, nullptr, "Node-API napi_get_property_names fail");
//        return nullptr;
//    }
//    
//    uint32_t length;
//    char name[300];
//    napi_get_array_length(env, result, &length);
//    
//    for (uint32_t i = 0; i < length; i++) {
//      napi_value element;
//      napi_get_element(env, result, i, &element);
//    
//      size_t str_size;
//      napi_get_value_string_utf8(env, element, name, 300, &str_size);
//    
//      // buffer 现在就是字符串
//      LOGD("property String: %{public}s\n", name);
//    }
//    
//    char frameName[] = "frame";
//    napi_value frame;
//    napi_get_named_property(env, argv[0], frameName, &frame);
//    
//    status = napi_get_property_names(env, frame, &result);
//    napi_get_array_length(env, result, &length);
//    
//    for (uint32_t i = 0; i < length; i++) {
//      napi_value element;
//      napi_get_element(env, result, i, &element);
//    
//      size_t str_size;
//      napi_get_value_string_utf8(env, element, name, 300, &str_size);
//    
//      // buffer 现在就是字符串
//      LOGD("frame property String: %{public}s\n", name);
//    }
//    
//    napi_value size_x;
//    status = napi_create_int32(env, 200, &size_x);
//    status = napi_set_named_property(env, frame, "x", size_x);
//    status = napi_set_named_property(env, argv[0], "frame", frame);
//    
//    napi_value invalidateFun;
//    
//    status = napi_get_named_property(env, argv[0], "invalidate", &invalidateFun);
//  LOGD("get function result: %{public}d\n", status);
//    
//    
//    status = napi_call_function(env, argv[0], invalidateFun, 0, nullptr, nullptr);
//    
//    LOGD("call function result: %{public}d\n", status);
//    
//    napi_value instance;
//    
//    napi_new_instance(env, argv[0], 1, nullptr, &instance);
//    
//    return nullptr;
//}


static napi_value nativeRegisterNodeConstructor(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
    
    if (argc < 1) {
        return nullptr;
    }
    OHRenderNode::SetNodeConstructor(env, argv[0]);
    return nullptr;
}


static napi_value nativeCreateRootNode(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value argv[2];
    napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
    void *context = nullptr;
    NodeDrawCallback callback = nullptr;
    callback = [](void *context, void *canvas){
        Testing::GetInstance().startTesting((SkCanvas *)canvas);
        return;
    };
    return OHRenderNode::CreateRootRenderNode(context, callback);
}

static napi_value nativeAddExternalNode(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
    OHEnv::GetInstance()->SetEnv(env);
    
    auto node = OHRenderNode::CreateExternalNode(argv[0]);
    Testing::GetInstance().addExternalNode(node);
    return nullptr;
}

static napi_value nativeOHRenderNodeDraw(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value argv[2];
    napi_status status;
    
    status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    if (status != napi_ok || argc < 2) {
        napi_throw_type_error(env, nullptr, "Expected canvas argument");
        return nullptr;
    }
    OHRenderNode::RenderNodeDraw(env, argv[0], argv[1]);
    return nullptr;
}

static napi_value nativeSetPixelRatio(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
    double ratio = 1.0;
    napi_get_value_double(env, argv[0], &ratio);
    OHRenderNode::SetPixelRatio(ratio);
    return nullptr;
}

static napi_value nativeOHRenderNotifyRedraw(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_status status;
    
    status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    if (status != napi_ok || argc < 1) {
        napi_throw_type_error(env, nullptr, "Expected renderNode argument");
        return nullptr;
    }
    OHRenderNode::RenderNodeNotifyRedraw(env, argv[0]);
    return nullptr;
}

static napi_value destroyAllNodeCache(napi_env env, napi_callback_info info) {
    Testing::GetInstance().destroyAllTestCasePictures();
    Testing::GetInstance().destroyExternalNode();
    return nullptr;
}


static napi_value nativeRegisterNodeStatusModifyConstructor(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
    
    if (argc < 1) {
        return nullptr;
    }
    NodeStatusModify::BuildInstance(env, argv[0]);
    return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeOnDraw", nullptr, OnDraw, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeAddPixelmap", nullptr, NativeAddPixelmap, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeTouchMove", nullptr, NativeTouchMove, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeAddPicData", nullptr, NativeAddPicData, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeAddGifData", nullptr, NativeAddGifData, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeSetFontPath", nullptr, NativeSetFontPath, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeRegisterNodeConstructor", nullptr, nativeRegisterNodeConstructor, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeRegisterNodeStatusModifyConstructor", nullptr, nativeRegisterNodeStatusModifyConstructor, nullptr, nullptr, nullptr, napi_default, nullptr },
        {"nativeCreateRootNode", nullptr, nativeCreateRootNode, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeOHRenderNodeDraw", nullptr, nativeOHRenderNodeDraw, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeSetPixelRatio", nullptr, nativeSetPixelRatio, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeOHRenderNotifyRedraw", nullptr, nativeOHRenderNotifyRedraw, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeDestroyAllNodeCache", nullptr, destroyAllNodeCache, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeAddExternalNode", nullptr, nativeAddExternalNode, nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);

    napi_status status;
    napi_value exportInstance = nullptr;
    OH_NativeXComponent *nativeXComponent = nullptr;

    status = napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
    LOGD("napi_get_named_property,status = %{public}d", status);
    if (status == napi_ok) {
        status = napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent));
        LOGD("napi_unwrap,status = %{public}d", status);
        if (status != napi_ok) {
            LOGE("napi_unwrap no ok");
        } else {
            g_nativeXcomponent = nativeXComponent;
            g_Xcallback.OnSurfaceCreated = OnSurfaceCreatedCB;
            g_Xcallback.OnSurfaceChanged = OnSurfaceChangedCB;
            g_Xcallback.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
            g_Xcallback.DispatchTouchEvent = DispatchEventCB;
            LOGD("set callback");

            OH_NativeXComponent_RegisterCallback(g_nativeXcomponent, &g_Xcallback);
        }
    }

    InitEGL();

    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
